
#include "GaussianMixtureChart.h"
#include <math.h>

GaussianMixtureChart::GaussianMixtureChart(int dim, double **limits, int num_slices) : Chart(dim, limits, num_slices)
{
}


GaussianMixtureChart::~GaussianMixtureChart()
{
}


void
GaussianMixtureChart::_store_gaussian(double *mean, double variance, int used_gaussian)
{
	// TODO: free it in the end!
	double *meancpy = (double *) calloc (_dim, sizeof(double));
	memcpy(meancpy, mean, _dim * sizeof(double));

	_means.push_back(meancpy);
	_variances.push_back(variance);
	_used_gaussian.push_back(used_gaussian);
}


void
GaussianMixtureChart::AddGaussian(double *mean, double variance, int used_gaussian)
{
	char *name = (char *) calloc (32, sizeof(char));
	sprintf(name, "Gaussian %d", (int) _means.size());

	vtkSmartPointer<vtkFloatArray> gaussian_column = vtkSmartPointer<vtkFloatArray>::New();
	gaussian_column->SetName(name);
	_table->AddColumn(gaussian_column);

	_store_gaussian(mean, variance, used_gaussian);
}


vtkSmartPointer<vtkChartXY>
GaussianMixtureChart::BuildChart()
{
	int i, j, k;

	// ***********************************************
	// NOTE: I don't know yet why, but I must set the
	// number of rows after adding all of the columns.
	// It's not cool because all the hard work became
	// centralized here. And it makes this method
	// really expensive.
	// ***********************************************
	_table->SetNumberOfRows(_num_rows);

	vtkSmartPointer<vtkChartXY> chart = vtkSmartPointer<vtkChartXY>::New();

	// fill the domains axis
	for (i = 0; i < _dim; i++)
		for (j = 0; j < _num_rows; j++)
			_table->SetValue(j, i, _limits[i][0] + j * _increments[i]);

	// fill the gaussians
	for (k = 0; k < _means.size(); k++)
	{
		double distance = 0.0;
		double probability = 0.0;

		for (int j = 0; j < _num_rows; j++)
		{
			distance = 0.0;

			for (int i = 0; i < _dim; i++)
				distance += pow((_limits[i][0] + j * _increments[i]) - _means[k][i], 2);

			probability = (1.0 / sqrt(pow(2.0 * M_PI, _dim) * _variances[k])) * exp((-1.0 / 2.0) * (1.0 / _variances[k]) * distance);

			_table->SetValue(j, _dim + k, probability);
		}

		vtkPlot *line = chart->AddPlot(vtkChart::LINE);

#if VTK_MAJOR_VERSION <= 5
		line->SetInput(_table, 0, _dim + k);
#else
		line->SetInputData(_table, 0, _dim + k);
#endif

		if (_used_gaussian[k])
			line->SetColor(255, 0, 0, 255);
		else
			line->SetColor(0, 0, 255, 255);

		line->SetWidth(1.0);
	}

	return chart;
}
